package cn.yunyichina.provider.authorize.service.impl;

import java.util.Map;

import cn.yunyichina.utils.commons.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import cn.yunyichina.provider.authorize.vo.HttpRequestVo;
import cn.yunyichina.provider.framework.annotation.validate.ValidateException;
import cn.yunyichina.provider.framework.annotation.validate.Validator;
import cn.yunyichina.provider.framework.dubbo.service.BaseService;
import cn.yunyichina.provider.framework.dubbo.service.CacheService;
import cn.yunyichina.provider.framework.dubbo.service.PayService;
import cn.yunyichina.provider.iface.entity.cache.SessionInfo;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingAppRelationResponse;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingAppRelationVo;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingResponse;
import cn.yunyichina.provider.iface.entity.pay.PaymentSettingVo;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.convert.MapUtils;
import cn.yunyichina.utils.convert.ObjectParser;
import cn.yunyichina.utils.security.AesEncryption;
import cn.yunyichina.utils.security.MD5Util;

/**
 * 验签
 *
 * @author zhangkewen
 */
@Service
public class SignatureServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(SignatureServiceImpl.class);

    /**
     * 签名验签
     *
     * @param data
     * @param sessionid
     * @return
     * @throws Exception
     */
    public ResponseObject validateSignature(String data, String sessionid) throws Exception {

        ResponseObject response = new ResponseObject();
        logger.info("签名验签-->method:validateSignature,data:" + data + "！");

        HttpRequestVo requestVo = JsonUtils.parseObject(data, HttpRequestVo.class);
        
        //查询method是否已经注册到后台数据库
        String apiDefine=requestVo.getMethod();
        if(StringUtils.isBlank(apiDefine)){
            response.setResultCodeAndMessage("9003", "传入的方法名:"+apiDefine+"为空");
            return response;
        }
        String valueResult=CacheService.getCacheClient().getApiCache(apiDefine);
        logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]从缓存获取值-->" + valueResult);

        Map<String, String> apiMap =null;
        if(StringUtils.isBlank(valueResult)){
            Response apiResponse=BaseService.callUnderlineFromInternal("yyt.base.api.get", "{\"api_define\":\""+apiDefine+"\"}");
            if(!"0".equals(apiResponse.getResultCode())){
                response.setResultCodeAndMessage("9003", "注意:请将方法"+requestVo.getMethod()+"注册到后台！");
                return response;
            }
            CacheService.getCacheClient().setApiCache(apiDefine,apiResponse.getResult());
            apiMap = JSON.parseObject(apiResponse.getResult(), Map.class);
        }else{
            logger.info(apiDefine+"命中缓存");
            apiMap=JSON.parseObject(valueResult,Map.class);
        }

        int signFlag = 0;
        if(apiMap.containsKey("sign_flag")){
            signFlag=ObjectParser.toInteger(apiMap.get("sign_flag")).intValue();
        }

        if(signFlag==1){
            response.setResultCodeAndMessage("0", "该接口不需要进行验签！");
            return response;
        }
        
        //做数据校验
        try {
            Validator.getInstance().validate(requestVo);
        } catch (ValidateException ex) {
            logger.error(requestVo.getAppId() + " 数据校验失败:" + ex.getMessage() + "|入参:" + data + "！",ex);
            response.setResultCodeAndMessage("9001", "数据校验失败:" + ex.getMessage() + "！");
            return response;
        }
        
        // 生成待签名的signStr
        Map<String, String> maps = JSON.parseObject(data, Map.class);
        String signStr = MapUtils.coverMap2SignString(maps);
        logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]生成的待签名字符串为-->" + signStr);
        
        String signKey ="";
        if("1".equals(requestVo.getRequestType())){//第三方对接
            // 查询支付的参数
            // 根据appId获取该配置的密钥,复用了hospitalCode
            String appId = requestVo.getAppId();
            String appCode = "alipay";

//            Map<String, String> searchMap = new HashMap<String, String>();
//            searchMap.put("hospital_code", appId);
//            searchMap.put("app_code", appCode);
            
            PaymentSettingAppRelationVo paymentRelationVo = new PaymentSettingAppRelationVo();
            paymentRelationVo.setPayMode((short) 4);
            paymentRelationVo.setOrgAppCode(appId);
            ResCommon<PaymentSettingAppRelationResponse> respTmp = PayService.getPayClient().getPaymentId(paymentRelationVo);
            if (!"0".equals(respTmp.getResultCode()) || respTmp.getResult() == null) {
                response.setResultCodeAndMessage("9003", "[appId:"+appId+",appCode:"+appCode+"]查询支付配置数据不存在");
                return response;
            }
            
            PaymentSettingVo paymentSettingVo = new PaymentSettingVo();
            paymentSettingVo.setId(respTmp.getResult().getPaymentId());
            ResCommon<PaymentSettingResponse> settingRespTmp = PayService.getPayClient().getPayKey(paymentSettingVo);

            if (!"0".equals(respTmp.getResultCode()) || settingRespTmp.getResult() == null) {
                response.setResultCodeAndMessage("9003", "[appId:"+appId+",appCode:"+appCode+"]查询支付配置数据不存在");
                return response;
            }
            
             signKey = settingRespTmp.getResult().getPayKey(); 
        }else if("3".equals(requestVo.getRequestType())){//用户登录
            SessionInfo sessionInfo=CacheService.getSessionInfo(requestVo.getSessionid());
            if(sessionInfo==null){
                response.setResultCodeAndMessage("12", "登录会话已过期，请重新登录!");
                return response;
            }
            
            signKey=sessionInfo.getSignKey();            
        }else{
            response.setResultCodeAndMessage("9003", "不支持该方法的验签，请检查配置！");
            return response;
        }
   
        // 根据sign_type做对应的加解密
        String encryptStr ="";
        if (requestVo.getSignType().intValue() == 1) {
            logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]获取AES加密的signKey-->" + signKey);
            encryptStr = AesEncryption.encrypt(signStr, signKey, signKey);
            logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]获取AES加密后的字符串为-->" + encryptStr);
      
        } else if (requestVo.getSignType().intValue() == 2) {
            response.setResultCodeAndMessage("9002", "暂不支持RSA签名验证！");
            return response;
        
        } else if(requestVo.getSignType().intValue()==3){
            encryptStr = signStr+signKey;
            logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]获取加signkey后的字符串为-->" + encryptStr);          
        
        }else{
            response.setResultCodeAndMessage("9002", "暂不支持其它签名验证！");
            return response;
        }
        
        String signCheck = MD5Util.string2MD5(encryptStr);
        String sign = requestVo.getSign();
        logger.info("[" + requestVo.getAppId() + "," + requestVo.getMethod() + "]-->原始的签名:" + sign + ",算出来的签名为:"
                + signCheck);

        if (sign.equals(signCheck)) {
            response.setResultCodeAndMessage("0", "签名验证成功！");
            return response;
        } else {
            response.setResultCodeAndMessage("9004", "签名验证失败！");
            return response;
        }
    }
}
